;/////////////////////////////////////////////////////////////////////
;This is the initializing part of project which construct the basic variable
;list for program running.
;The major function here is: constructvarlistplus, retrieveplus
;"retrieveplus" is traversing input list and pickup all variables and remove 
;both repetition and its negated format of variable name.
;The side effect is that it also count the occurrance of each variable. Add
;+1 for each variable and -1 for each negated format. And finally store the 
;sum of the occurrance count and stores it in a global variable gVarCountList
;
;"constructvarlistplus" initialize variable list(different from occurrance 
;count list) and sort variable list according to the absolute value of occurrance
;of each variable, so that backtracking function will choose variable by this 
;sequence. And choose truth assignment by referencing the occurrance count value.
;If it is positive, it choose true first, otherwise verse versa.
;
;

(load "utility.txt")
(load "testcases.txt")


;(define test10001 '(AND M N (NOT A) (OR P Q R) (OR A B)(OR P Q) C F))

(define gVarCountList '())

(define varcountcomp
	(lambda (var1 var2)
		(> (abs (cdr var1)) (abs (cdr var2)))
	)
)

(define sortvarcountlist
	(lambda (ls)
		((generic_sort varcountcomp) ls)
	)
)

(define wrapdoaddtolist
	(lambda (x ls)
		(if (is_not x)
			(doaddtolist (cons (cadr x) -1) ls)
			(doaddtolist (cons x 1) ls)
		)
	)
)

(define doaddtolist
	(lambda (sym ls)
		(begin ;(pp(list "doaddtolist sym=" sym  "ls=" ls))
		(if (null? ls)
			(list sym)
			(if (equal? (car sym) (car (car ls)))
				(begin ;(pp(list "doaddtolist (cdr sym)=" (cdr sym) "(cdr(car ls))=" (cdr(car ls))))
					(cons (cons (car sym)(+ (cdr (car ls))(cdr sym))) (cdr ls))
				)
				(begin ;(pp(list "doaddtolist (car ls)=" (car ls) "(cdr ls)=" (cdr ls)))
					(cons (car ls)(doaddtolist sym (cdr ls)))
				)
			)
		))
	)
)


(define mergetwolistplus
	(lambda (ls1 ls2)
		(begin ;(pp(list "mergetwolistplus ls1=" ls1 "ls2=" ls2))
		(if (null? ls1)
			ls2
			(mergetwolistplus (cdr ls1)(doaddtolist (car ls1) ls2))
		))
	)
)
			
;traverse input list collecting variable name and occurrance count.
;
(define retrieveplus
	(lambda (ls)
		(begin ;(pp(list "retrieveplus ls=" ls))
		(if (null? ls)
			'()
			(if (not_symbol (car ls))
				(mergetwolistplus (retrieveplus (car ls)) (retrieveplus (cdr ls)))
				(if (or (is_and  ls) (is_or  ls))
					(retrieveplus (cdr ls))
					(wrapdoaddtolist (car ls) (retrieveplus (cdr ls)))
				)
			)
		))
	)
)



(define symbolcomp
	(lambda (ls1 ls2)
		(if (string=? (symbol2string ls1)(symbol2string ls2))
			(if (and (is_not ls1)(symbol? ls2));  define "not A" < "A"
				#t
				#f ;all other cases assume they are not ls1<ls2
			)
			(string<? (symbol2string ls1)(symbol2string ls2))
		)
	)
)

(define getcountvalue
	(lambda (x)
		(cdr (assq x gVarCountList))
	)
)

(define choosevarbycount
	(lambda (satlst)
		(if (null? (cdr satlst))
			(car(car satlst))
			(let ((result (choosevarbycount (cdr satlst))))
				(if (< (abs (getcountvalue (car (car satlst))))(abs(getcountvalue result)))
					result
					(car (car satlst))
				)
			)
		)
	)
)

(define satlst '((A . #t) (B . #t)))

(define initialpair
	(lambda (sym)
		(cons sym 'N)
	)
)

(define initialpairplus
	(lambda (sym)
		(cons (car sym) 'N)
	)
)

(define initvarlistplus
	(lambda (ls)
		(map initialpairplus ls)
	)
)

;The function to construct variable list and sorted according to absolute value of occurance
;count value. And it also initialize the variable list to "unset" or 'N
;
(define constructvarlistplus
	(lambda (ls)
		(let ((result (retrieveplus ls)))
			(begin
				(set! result (sortvarcountlist result))
				(set! gVarCountList result)				
				(initvarlistplus result)
			)
		)
	)
)
			


(define addtolist
	(lambda (x ls)
		(if (is_not x)
			(addtolist (cadr x) ls)
			;(begin (pp (list "addtolist x=" x "ls=" ls))
			(if (null? ls)
				(list  x)
				(if (or(is_negate x (car ls))(equal? x (car ls)))
					ls
					(cons (car ls)(addtolist x (cdr ls)))
				)
			)
		)
		;)
	)
)

(define symbolsort
	(lambda (ls)
		((generic_sort symbolcomp) ls)
	)
)


(define mergetwolist
	(lambda (ls1 ls2)
		(if (null? ls1)
			ls2
			(mergetwolist (cdr ls1)(addtolist (car ls1) ls2))
		)
	)
)			

; this function will remove all not or and, only retrieve symbols and put in a list
(define retrieve
	(lambda (ls)
		(if (null? ls)
			'()
			(if (not_symbol (car ls))
				(mergetwolist (retrieve (car ls)) (retrieve (cdr ls)))
				(if (or (is_and  ls) (is_or  ls))
					(retrieve (cdr ls))
					(addtolist (car ls) (retrieve (cdr ls)))
				)
			)
		)
	)
)

(define initvarlist
	(lambda (ls)
		(map initialpair ls)
	)
)

(define constructvarlist
	(lambda (ls)
		(initvarlist (retrieve ls))
	)
)
